#include <REGX52.H>
#include <INTRINS.H>
#include "LCD1602.h"

//用P1 是自带上拉电阻的，P0不行
sbit DS1302_CE = P1 ^ 2;   // DS1302 的使能端
sbit DS1302_IO = P1 ^ 1;   // DS1302 的数据信号
sbit DS1302_SCLK = P1 ^ 0; // DS1302 的时钟信号

#define REG_SEC_R 0x81
#define REG_SEC_W 0x80

#define REG_MIN_R 0x83
#define REG_MIN_W 0x82

#define REG_HOUR_R 0x85
#define REG_HOUR_W 0x84

#define REG_DATE_R 0x87
#define REG_DATE_W 0x86

#define REG_MON_R 0x89
#define REG_MON_W 0x88

#define REG_YEAR_R 0x8D
#define REG_YEAR_W 0x8C

#define REG_WRITE_PROTECT_W 0X8E

// 向DS1302写入一个字节
void DS1302_WriteByte(unsigned char sent_data)
{
    unsigned char i = 0;
    for (i = 0; i < 8; i++)
    {
        DS1302_SCLK = 0;
        if (sent_data & (0x01 << i))
        {
            DS1302_IO = 1;
        }
        else
        {
            DS1302_IO = 0;
        }
        DS1302_SCLK = 1;
    }
    DS1302_SCLK = 0;
}

// 从DS1302读一个字节
unsigned char DS1302_ReadByte()
{
    unsigned char read_data = 0;
    unsigned char i = 0;
    for (i = 0; i < 8; i++)
    {
        if (DS1302_IO)
        {
            read_data |= 0x01 << i;
        }
        else
        {
            read_data &= ~(0x01 << i);
        }
        // 先读到数据,再让时钟信号先拉高，再拉低
        DS1302_SCLK = 1;
        DS1302_SCLK = 0;
    }
    return read_data;
}

// 从DS1302 读取寄存器内容
unsigned char ReadReg(unsigned char cmd)
{
    unsigned char result = 0;
    DS1302_CE = 1; // 使能
    DS1302_WriteByte(cmd);
    result = DS1302_ReadByte();
    DS1302_CE = 0;
    return result;
}

// DS1302 写寄存器
void WriteReg(unsigned char cmd, unsigned char write_data)
{
    DS1302_CE = 1; // 使能
    DS1302_WriteByte(cmd);
    DS1302_WriteByte(write_data);
    DS1302_CE = 0;
}

// 二进制数转BCD码
// binary不得大于99
unsigned char BinaryToBCD(unsigned char binary)
{
    unsigned char bcd = 0;
    bcd = ((binary / 10) << 4) | (binary % 10);
    return bcd;
}

// BCD码转二进制
unsigned char BCDToBinary(unsigned char bcd)
{
    unsigned char binary = 0;
    unsigned char high = bcd >> 4;
    unsigned char low = bcd & 0x0f;
    binary = high * 10 + low;
    return binary;
}

// 设置时间
void SetTime(unsigned char year, unsigned char month, unsigned char date,
             unsigned char hour, unsigned char min, unsigned char sec)
{
    unsigned char tmp = 0x0;
    
    // 关闭写保护
    WriteReg(REG_WRITE_PROTECT_W, 0x00);

    // 写入时间
    tmp = BinaryToBCD(year);
    WriteReg(REG_YEAR_W, tmp);

    tmp = BinaryToBCD(month);
    WriteReg(REG_MON_W, tmp);

    tmp = BinaryToBCD(date);
    WriteReg(REG_DATE_W, tmp);

    // 默认为24小时制,bit7=0
    tmp = BinaryToBCD(hour);
    WriteReg(REG_HOUR_W, tmp);

    tmp = BinaryToBCD(min);
    WriteReg(REG_MIN_W, tmp);

    // 秒寄存器的 bit7 = 0 开始计时
    tmp = BinaryToBCD(sec);
    WriteReg(REG_SEC_W, tmp);

    // 开启写保护
    WriteReg(REG_WRITE_PROTECT_W, 0x80);
}

// 读取时间
void ReadTime(unsigned char *year, unsigned char *month, unsigned char *date,
              unsigned char *hour, unsigned char *min, unsigned char *sec)
{
    unsigned tmp = 0x0;
    tmp = ReadReg(REG_YEAR_R);
    *year = BCDToBinary(tmp);

    tmp = ReadReg(REG_MON_R);
    *month = BCDToBinary(tmp);

    tmp = ReadReg(REG_DATE_R);
    *date = BCDToBinary(tmp);

    tmp = ReadReg(REG_HOUR_R);
    *hour = BCDToBinary(tmp);

    tmp = ReadReg(REG_MIN_R);
    *min = BCDToBinary(tmp);

    tmp = ReadReg(REG_SEC_R);
    *sec = BCDToBinary(tmp);
}

void ShowTime()
{
    unsigned char year, month, date, hour, min, sec;
    unsigned char i = 1;
    ReadTime(&year, &month, &date, &hour, &min, &sec);

    LCD_ShowString(1, 1, "Time is: 20");
    LCD_ShowNum(1, 12, year, 2);

    LCD_ShowNum(2, i, month, 2);
    i += 2;
    LCD_ShowChar(2, i, '-');
    i += 1;
    LCD_ShowNum(2, i, date, 2);
    i += 2;
    LCD_ShowChar(2, i, ' ');
    i += 1;

    LCD_ShowNum(2, i, hour, 2);
    i += 2;
    LCD_ShowChar(2, i, ':');
    i += 1;
    LCD_ShowNum(2, i, min, 2);
    i += 2;
    LCD_ShowChar(2, i, ':');
    i += 1;
    LCD_ShowNum(2, i, sec, 2);
}

void Delay1000ms();

void main()
{
    //如果不加这三行，会导致无法写入！
    //因为端口复位后处于高电平/悬空状态，导致 DS1302 的 CE 先被误触发
    P1_0 = 0;
    P1_1 = 0;
    P1_2 = 0;
    LCD_Init();
    LCD_Clear();
    Delay1000ms();
    SetTime(25,9,2,16,51,50);
    while (1)
    {
        ShowTime();
        Delay1000ms();
    }
}

void Delay1000ms() //@11.0592MHz
{
    unsigned char i, j, k;

    _nop_();
    i = 8;
    j = 1;
    k = 243;
    do
    {
        do
        {
            while (--k)
                ;
        } while (--j);
    } while (--i);
}
